#include<REGX52.H>

//效果：LED环形流水灯
//知识点：LED低电平点亮（上电默认高电平）、自定义延时函数

void Delay1ms(unsigned int xms)	//@11.0592MHz，自定义延时函数
{
	unsigned char data i, j;
	while(xms)
	{
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);//前面几行是延时1ms的代码
	xms--;
	}
}

//void main()	//基础环形流水灯
//{
//	while(1)
//	{
//		P2 = 0xfe;	//1111 1110
//		Delay1ms(500);	//500赋值给xms
//		P2 = 0xfd;	//1111 1101
//		Delay1ms(500);	
//		P2 = 0xfb;	//1111 1011
//		Delay1ms(500);
//		P2 = 0xf7;	//1111 0111
//		Delay1ms(500);
//		P2 = 0xef;	//1110 1111
//		Delay1ms(500);
//		P2 = 0xdf;	//1101 1111
//		Delay1ms(500);
//		P2 = 0xbf;	//1011 1111
//		Delay1ms(500);
//		P2 = 0x7f;	//0111 1111
//		Delay1ms(500);
//	}
//}

//void main()	//按键控制开关
//{
//	while(1)
//	{
//		if(P3_1==0)
//		{
//			Delay1ms(20);	//按下消抖
//			while(P3_1==0);	//按下已消抖，若一直按下，则执行空语句
//			Delay1ms(20);	//松手消抖
//			
//			P2_0=~P2_0;
//		}
//	}
//}

//void main()	//独立按键控制LED显示二进制
//{
//	unsigned char LEDNum=0;	//常用unsigned char定义寄存器，因为unsigned char长度与单片机一致，都是8位

//	while(1)
//	{
//		if(P3_1==0)
//		{
//			Delay1ms(20);
//			while(P3_1==0);
//			Delay1ms(20);	//以上为按键消抖全过程
//			
//			LEDNum++;
			//LEDNum取反后对应P2的输出
//			P2=~LEDNum;	//不能写P2=~P2，因为IO口上电默认高电平，这样的第一次结果为全亮，即0000 0000
//		}
//	}
//}

//按键K1左移，K1是P3_1
//按键K2右移，K2是P3_0
//unsigned char LEDNum=0;

//void main()	//独立按键控制led的移位
//{
//	P2=~0x01;	//设置开始D1亮
//	while(1)
//	{
//		if(P3_1==0)	//	左移
//		{
//			Delay1ms(20);
//			while(P3_1==0);	//等待释放
//			Delay1ms(20);	
//			
//			
//			LEDNum--;
//			if(LEDNum==255) //此处为255，而非0，是因为LEDNum--后，应该为255（LEDNum的类型是unsigned char）
//				LEDNum=7;
//			P2=~(0x01<<LEDNum);	//左移
//		}
//		
//		if(P3_0==0)
//		{
//			Delay1ms(20);
//			while(P3_0==0);
//			Delay1ms(20);
//			
//			LEDNum++;
//			if(LEDNum>7)    //此处应该为7
//				LEDNum=0;
//			P2=~(0x01<<LEDNum); //左移
//		}
//	}
//}

//呼吸灯（出这段代码外，都要用到第一个自定义定时器函数）
// sbit LED=P2^0;

// void Delay(unsigned int t)
// {
// 	while(t--);
// }

// void main()
// {
// 	unsigned char Time,i;
// 	for(Time=0;Time<100;Time++) //暗变亮
// 	{
// 		for(i=0;i<20;i++)   //1次时间太短，就持续20次
// 		{
// 			LED=0;
// 			Delay(Time);    //Time加上100-Time一定要是定值（PWM），所以这样定义变量
// 			LED=1;
// 			Delay(100-Time);	
// 		}
// 	}
	
// 	for(Time=100;Time>0;Time--) //亮变灭
// 	{
// 		for(i=0;i<20;i++)
// 		{
// 			LED=0;
// 			Delay(Time);
// 			LED=1;
// 			Delay(100-Time);	
// 		}
// 	}
// }


//实现按键长按和短按控制LED亮灭，既要有亮的过程，也要有灭的过程！
//int main()
//{
//	while(1)
//	{
//		if(P3_1==0)//检测按键按下
//		{
//			Delay1ms(20);//消抖
//				if(P3_1==0)//确认按键按下
//				{
//					P2_0=0;
//				}
//				//等待按键释放
//				while(P3_1==0);
//				Delay1ms(20);
//				while(P3_1==0);//确认松开
//				P2_0=1;
//		}	
//	}
//}

//长按按键一直点亮，短按切换亮灭,is_processed确保了一直亮和亮灭只能触发一个
sbit KEY=P3^1;
sbit LED=P2^0;

int main()
{
	unsigned int Long_Time=1000;//单位是ms,按按键时间大于1000ms则为长按,不能用unsigned char
	unsigned int press_time=0;
	bit is_processed=0;	//0：表示当前按键事件未被处理,1：表示已处理过
	
	LED=1;//初始状态LED灭
	
	while(1)
	{
		if(KEY==0)//检测按下
		{
			Delay1ms(20);
			if(KEY==0)//确定按下
			{
				press_time=0;//清空
				is_processed = 0;
			}
			
				//按住期间计时
				while(KEY==0)
				{
					Delay1ms(20);
					press_time+=20;
					
					//按键释放后再判断长短按
					//实时长按检测
					//短按判断在 while(KEY==0) 循环内执行，会导致按键按住期间LED快速闪烁
					if(press_time>=Long_Time&&!is_processed)//等价于key_processed == 0
					{
						LED=0;//长按
						is_processed=1;//标记已处理
						while(KEY == 0); // 等待按键释放
						Delay1ms(20);    // 释放消抖
					}
				}
			
			//按键释放后处理短按
			if(!is_processed && press_time<Long_Time)
				LED=!LED;//短按，改变亮灭状态
				while(KEY == 0); // 等待按键释放
				Delay1ms(20);    // 释放消抖
		}
	}
}
//is_processed 在此处的作用相当于一个状态过滤器，确保：
//1.只有未被长按处理过的按键事件才能进入短按判断
//2.严格区分长按和短按的触发条件
//3.增强代码在边界条件下的鲁棒性（如临界时间、抖动等情况）
